package com.xzzz.irda.auth.core.filter.impl;

import com.xzzz.irda.auth.core.AuthBaseConfiguration;
import com.xzzz.irda.auth.core.AuthBaseProperties;
import com.xzzz.irda.auth.core.authorization.AuthContext;
import com.xzzz.irda.auth.core.authorization.Authorization;
import com.xzzz.irda.auth.core.constants.AuthConstant;
import com.xzzz.irda.auth.core.exception.AuthException;
import com.xzzz.irda.auth.core.exception.AuthRCode;
import com.xzzz.irda.auth.core.filter.AuthFilter;
import com.xzzz.irda.auth.core.filter.AuthFilterChain;
import com.xzzz.irda.auth.core.util.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

@Slf4j
public class AuthorizationUniqueFilter implements AuthFilter {

    /**
     * 配置文件内容
     */
    @Autowired
    private AuthBaseProperties properties;

    /**
     * 公用基础配置
     */
    @Autowired
    private AuthBaseConfiguration authBaseConfiguration;

    /**
     * 执行过滤器
     *
     * @param request         request
     * @param response        response
     * @param authFilterChain 过滤器链
     * @throws IOException      io
     * @throws ServletException servlet
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, AuthFilterChain authFilterChain) throws IOException, ServletException {
        log.debug("[AUTHORIZ] filter({}) 唯一授权校验", getOrder());

        boolean isWhiteList = Boolean.TRUE.equals(request.getAttribute(AuthConstant.WHITE_LIST_ATTRIBUTE_KEY));
        if (isWhiteList) {
            return;
        }

        // 根据 token 取出 Redis 中的授权数据
        Authorization authorization = AuthContext.getContext();

        /*
         * 如果不是白名单请求,则判断授权信息是否有效
         *    1. 如果授权服务方允许多设备登录, 则每次登录获取的 token 是相同的, 即 unique 不会被覆盖
         *    2. 如果授权服务方不允许多设备登录, 则每次登录的 token 是不同的, 即 unique 会被覆盖
         */
        String uniqueToken = authBaseConfiguration.getAuthorizationRepository()
                .getUniqueToken(TokenUtil.buildUniqueTokenKey(authorization));
        // 用户正在使用的 token 没有过期, 但没有有效 token, 则是未授权的请求, 通常不会出现该情况, token 与有效 token 的过期差不会太大
        if (uniqueToken == null) {
            throw new AuthException(AuthRCode.INVALID_TOKEN);
        }

        // 用户的的有效授权信息与当前使用的授权信息不相符, 则说明该账号在别处登录, 替换了有效授权信息
        if (!uniqueToken.equals(authorization.getAccessToken().getToken())) {
            throw new AuthException(AuthRCode.ANOTHER_DEVICE_LOGIN);
        }

        authFilterChain.doFilter(request, response);
    }

    @Override
    public int getOrder() {
        return AuthConstant.Filter.AUTHORIZATION_UNIQUE_FILTER;
    }
}